package ch.unifr.diva.multimodals.spherex;

import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Random;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

/**
 * "Main" interface for the user, where the actual interaction takes place and the user is informed about 
 * @author Dani
 *
 */
public class NetConfigurationActivity extends Activity {
	
	public static final int IP_ADDRESS=10; //Identifier for the procedure of setting the IP address

	
	private static final String APPEND_TO_CONSOLE_INFO = "appendToConsoleInfo";//Identifier for LogCat to show that the following text was displayed on console
	

	//Declaration of visual elements
	private SeekBar gravity, friction, bounce; //The three "actual" adjustable physical parameters
	Button connect, disconnect;
	private Button pauseResumeGame, resetGame, quitGame;
	private TextView console, ipValue, portValue;
	ImageView connectionStatus;
	@SuppressWarnings("unused")
	private ScrollView scrollView;
	IpSetter s = new IpSetter();//Initialize the IP configuration screen
	
	//Declaration of communication elements
	PrintWriter output;
	OutputStream out;
	Socket socket;
	private String ip;
	private int port;
	private TestingThread t;//To continuously test the connection


	private MultimodalDialog md;
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    	//Android setup
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
       
        
        //Get the references to the elements on the screen
        ipValue = (TextView) findViewById(R.id.ipValue);
        portValue = (TextView) findViewById(R.id.portValue);
        
        //Initialize multimodal dialog
        this.md=new MultimodalDialog(this);
        
        //Retrieve and set up buttons
        connect = (Button) findViewById(R.id.connect);
        connect.setOnClickListener(new OnClickListener(){
        	/*Try to connect: disable the connect button, then launch a parallel testing thread that
        	 * regularly verifies the connection. Start that thread.
        	*/
			@Override
			public void onClick(View v) {
				connect.setEnabled(false);
				t = new TestingThread(NetConfigurationActivity.this);
				t.setRunning(true);
				t.start();
				}});
        disconnect = (Button) findViewById(R.id.disconnect);
        disconnect.setOnClickListener(new OnClickListener(){
        	/*
        	 * Disconnect: interrupt the running thread that checks the connection and disable the bars
        	 */
			@Override
			public void onClick(View v) {
				t.setRunning(false);
				setEnabledConnection(false, true);
			}
        });
        pauseResumeGame = (Button) findViewById(R.id.pauseResume);
        pauseResumeGame.setOnClickListener(new OnClickListener(){
        	@Override
        	public void onClick(View arg0) {
        		sendGameState(getString(R.string.game_state_pause));
        	}
        });
        
        resetGame= (Button) findViewById(R.id.reset);
        resetGame.setOnClickListener(new OnClickListener(){
        	@Override
        	public void onClick(View arg0) {
        		sendGameState(getString(R.string.game_state_reset));
        	}
        });
        quitGame= (Button) findViewById(R.id.quit);
        quitGame.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View arg0) {
confirmExit();
			}
        });
        
        
        
        //Get the references to the elements on the screen
        connectionStatus = (ImageView) findViewById(R.id.connectionStatus);
        scrollView = (ScrollView) findViewById(R.id.consoleScrollView);
        console = (TextView) findViewById(R.id.consoleTextView);
        gravity = (SeekBar) findViewById(R.id.gravityBar);
        friction = (SeekBar) findViewById(R.id.frictionBar);
        bounce= (SeekBar) findViewById(R.id.bounceBar);
        

        //Activate the listeners on the three bars
        gravity.setOnSeekBarChangeListener(new MyOnSeekBarChangeListener(getString(R.string.gravity), this));
        friction.setOnSeekBarChangeListener(new MyOnSeekBarChangeListener(getString(R.string.friction), this));
        bounce.setOnSeekBarChangeListener(new MyOnSeekBarChangeListener(getString(R.string.bounce), this));
 
        //Disabled connection when starting
        setEnabledConnection(false, false);
}
    


	/**
     * Set the main menu
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    	MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main_menu, menu);
        return true;
    }
    

    /**
     * Capture the "back keystroke" event to show the exit dialog
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            confirmExit();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
    
    /**
     * Launch events, depending on which menu element was selected
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    	md.shortConfirm();
        // Handle item selection
        switch (item.getItemId()) {
            case R.id.main_menu_ip_config:
            	//Start the IP configuration activity
            	Intent intent = new Intent(this, IpSetter.class);
                startActivityForResult(intent, IP_ADDRESS);
                return true;
                //Donate function
                case R.id.main_menu_donate:
                	new AlertDialog.Builder(this).setMessage(R.string.donated).setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							dialog.cancel();
						}
					}).create().show();
                	return true;
                	//Exit dialog
                	case R.id.main_menu_quit:
                		confirmExit();
                		return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    //Alternative "back keystroke" event capture: for higher Android versions
    @Override
    public void onBackPressed() {confirmExit();}  
    

    /**
     * Display the exit confirmation dialog 
     */
private void confirmExit() {
	md.confirm(false, true);//Alarm user by activating "negative" confirmation pattern
	AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage(R.string.confirm_quit)
           .setCancelable(false)
           .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
        	   //User confirmed
               public void onClick(DialogInterface dialog, int id) {
            	   NetConfigurationActivity.this.exit();
               }
           })
           //User cancelled
           .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
               }
           }).setNeutralButton(R.string.maybe, new DialogInterface.OnClickListener() {
        	   //Maybe-selection feature
			public void onClick(DialogInterface dialog, int which) {
				final boolean quit=new Random(System.nanoTime()).nextInt(2)==1? true:false;
				AlertDialog.Builder builder = new AlertDialog.Builder(NetConfigurationActivity.this);
				builder.setMessage(getString(R.string.maybe_explanation)+"\n"+ getString(quit? R.string.maybe_decided_positive:R.string.maybe_decided_negative)+"\n").setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						if(quit)
							NetConfigurationActivity.this.exit();
						else
							dialog.cancel();
					}
				});
				AlertDialog alert = builder.create();
				alert.show();
			}
		});//End maybe-selection feature
    AlertDialog alert = builder.create();
    alert.show(); //Display the created dialog
	}

/**
 * Method to quit the application (after having confirmed). Sending the command to the application, if possible.
 */
protected void exit() {
	try{
		String description=getString(R.string.main_quit);
		//Use the socket's output stream and the there attached printwriter
		String msg = getString(R.string.gamestate_changed)+description;
		out = socket.getOutputStream();
		output = new PrintWriter(out);
		output.print("GameState:"+0);
		output.flush();
		out.flush();
		appendToConsole(msg);
	} catch (Exception e) {
		e.printStackTrace();
	}
	System.exit(0);
	}

/**
 * Get the result from child activities
 */
@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);
	String text;
		switch(requestCode){
		case IP_ADDRESS:
			//Get the result from the IP settings
			switch(resultCode){
			case RESULT_OK:
				//User modified IPs: store IP and port values
				this.ip = data.getStringExtra(IpSetter.NEW_IP);
				ipValue.setText(ip);
				this.port = data.getIntExtra(IpSetter.NEW_PORT, 0);
				portValue.setText(Integer.toString(port));
				text = getString(R.string.ipAddress_confirmOk)+" "+ip+":"+port;
				appendToConsole(text);
				//Inform the user about new settings
				Toast.makeText(NetConfigurationActivity.this, text, Toast.LENGTH_LONG).show();
				connect.setEnabled(true);
				md.confirm(true, true);
				break;
			case RESULT_CANCELED:
				//User cancelled modification
				text= getString(R.string.ipAddress_confirmCancel);
				appendToConsole(text);
				//Inform the user about cancellation
				Toast.makeText(this,text, Toast.LENGTH_LONG).show();
				md.confirm(false, true);
				break;
			}
			break;
			default:
				break;
		}
		
	}


/**
 * Auxiliary method to set connection state (enable/ disable user control elements) 
 * @param enabled If true, then all bars are enabled (editable)
 * @param enableConnectButton If true, the user may press the "connect" button
 */
public void setEnabledConnection(boolean enabled, boolean enableConnectButton){
	connect.setEnabled(enableConnectButton);
	disconnect.setEnabled(enabled);
	pauseResumeGame.setEnabled(enabled);
	resetGame.setEnabled(enabled);
	connectionStatus.setImageDrawable((Drawable) getResources()
		.getDrawable(enabled? android.R.drawable.presence_online : android.R.drawable.presence_busy));
	gravity.setEnabled(enabled);
	friction.setEnabled(enabled);
	bounce.setEnabled(enabled);
}


/**
 * Transmit a new bar value to the output stream, which will be read by the application
 * @param id The name of the bar
 * @param progress The new value of the bar
 */
public void sendNewValue(String id, float progress){
	
    try {
    	//Use the socket's output stream and the there attached printwriter
    	String msg = getString(R.string.progress_changed)+id+": "+progress;
    	//socket = new Socket(ip.getText().toString(), Integer.parseInt(port.getText().toString()));
		out = socket.getOutputStream();
	    output = new PrintWriter(out);
		output.print(id+":"+progress);
	    output.flush();
	    out.flush();
	    appendToConsole(msg);
	    //output.close();
	    //socket.close();
	    md.confirm(true, true);
	} catch (Exception e) {
		setEnabledConnection(false, true);
		md.confirm(false, true);
	}
           

}
/**
 * Transmit a new game state
 * @param value The new game state
 */
public void sendGameState(String value){
	try {
		String description="";
		int enumVal=0;
		//Create a senseful description for logging
		if(value.equals(getString(R.string.game_state_pause))){
				description=getString(R.string.main_pause);
				enumVal=2;
				
		}
		else if(value.equals(getString(R.string.game_state_resume))){
			description=getString(R.string.main_resume);
			enumVal=3;
		}
		else if(value.equals(getString(R.string.game_state_quit))){
			confirmExit();
			return;
		}
		else if(value.equals(getString(R.string.game_state_reset))){
			description=getString(R.string.main_reset);
			enumVal=5;
		}
		
		//Use the socket's output stream and the there attached printwriter
		String msg = getString(R.string.gamestate_changed)+description;
		out = socket.getOutputStream();
		output = new PrintWriter(out);
		output.print("GameState:"+enumVal);
		output.flush();
		out.flush();
		appendToConsole(msg);
		md.confirm(true, true);
	} catch (Exception e) {
		setEnabledConnection(false, true);
		md.confirm(false, true);
	}
	
	
}


/**
 * Display text on the GUI
 * @param text The text to display
 */
public void appendToConsole(final String text){
Log.d(APPEND_TO_CONSOLE_INFO, text);
console.setText(text+"\n"+console.getText());
}

//IP getter
public String getIp() {
	return ip;
}

//Port getter
public int getPort() {
	return port;
}



}

    
